// -*- mode:C; tab-width:2; indent-tabs-mode:nil;  -*-

#include <stdlib.h>
#include "hashTable.h"
#include "linked_list.h"

#include "lockDef.h"
#include "factory.h"

INSTANTIATETYPE( hashTable_t ,  
    int table_size;
  	linked_list_t *table;
  	hash_fn_t hash_function;
  	hash_key_cmp_fn_t key_comparator_function;
)

CREATEMANAGER(hashTable_t)

hashTable_t 
hashTable_create(int size, hash_fn_t hashFunc, hash_key_cmp_fn_t keyCmpFunc){
	hashTable_t h = hashTable_t_acquire();
  if (!h) {
    printf("Hashtable acquire failed!\n");
    exit(1);
  }
	h->table_size = size;
	h->table = (linked_list_t*)malloc(sizeof(linked_list_t)*size); 
  int i=0;
  for(i=0; i<size;i++){
    h->table[i]=NULL;
  }
	h->hash_function = hashFunc;
	h->key_comparator_function=keyCmpFunc;
	return h;
}


int 
hashTable_destroy( hashTable_t h,hash_key_destroy_fn_t destroyKeyFunc, hash_value_destroy_fn_t destroyValFunc){
	if (h==NULL) return 1;//fail because hashtable is NULL
	linked_list_t chain;
	int i;
	for(i=0;i < h->table_size;i++){
		chain = *(h->table+i);
		linked_list_destroy(chain, destroyKeyFunc,destroyValFunc);
	}
	free(h->table);
	hashTable_t_release(h,NULL);
	return 0;
}
 
int addHashItem(hashTable_t h, void* key, void* value, hash_key_destroy_fn_t destroyKeyFunc, hash_value_destroy_fn_t destroyValFunc){
	if (h == NULL) {
		return 1;//fail because hashtable is NULL
	}
	
	int table_size = h->table_size;
	unsigned int index = (h->hash_function(key))%table_size;
	linked_list_t chain = *(h->table+index);
	//check if the chain is NULL
	if (chain == NULL){
	  chain = linked_list_create(h->key_comparator_function);
	  *(h->table+index) = chain;
	}
	linked_list_update_or_append(chain, key , value, destroyKeyFunc, destroyValFunc);
	return 0;
}

void* lookupHashItem(hashTable_t h, void* key){
	if (h == NULL) return NULL;//fail because hashtable is NULL
  int table_size = h->table_size;
	int index = (h->hash_function(key))%table_size;
	linked_list_t chain = *(h->table+index);
	if (chain==NULL){
	  return NULL;
	}else{
	  return linked_list_key_search(chain,key);
	}
}

static
boolean_t
show_one(linked_list_element_t k,linked_list_element_t e, linked_list_pfapply_closure_t cl) 
{
  printf(" [%d,%d] ",*(int*)k, *(int*)e);
  *(int*)cl = *(int*)cl + 1;
  return TRUE;
}

void
hashtable_debug(hashTable_t h){
  printf("array size = %d\n", h->table_size);
  linked_list_t *cur = h->table;
  int i=0;
  while(i < h->table_size){
    linked_list_t linked_list = *cur;
    i++;
    //int size = queue_size(linked_list);
    if (linked_list!=NULL){
      int x=0;
      printf("i = %d\n", i);
      linked_list_apply(linked_list, show_one, &x);
      printf("\n");
    }
    cur++;
  }
}
